/*
 * @Author: hongbin
 * @Date: 2022-12-01 11:42:52
 * @LastEditors: hongbin
 * @LastEditTime: 2022-12-03 21:22:46
 * @Description:临时对话
 */
import { FC, Fragment, memo, MouseEvent, useCallback, useEffect, useMemo, useRef, useState } from "react";
import styled from "styled-components";
import { useAuth } from "../../../context/AuthProvide";
import { CanRun } from "../../../helper";
import { INearbyUser, otherUserList } from "../../../meta/helper/OtherUser";
import { SocketManager } from "../../../socket";
import { fadeIn, flexCenter, FlexDiv } from "../../../styled";
import Dialogue from "./Dialogue";
import MessageList from "./MessageList";

interface IProps {}

export interface ITemporaryMessage {
    content: string;
    sender: string;
    senderName: string;
}

/**
 * 临时对话组件
 */
const TemporaryDialogue: FC<IProps> = () => {
    const { user } = useAuth();
    const [nearbyUsers, setNearbyUsers] = useState<INearbyUser[]>([]);
    const payloadIndex = useRef(0);
    const [selectId, setSelectId] = useState("");
    const [selectIndex, setSelectIndex] = useState(-1);
    const selectIndexRef = useRef(-1);
    const inputting = useRef(false);
    const selectIdRef = useRef("");
    const inputRef = useRef<HTMLInputElement>(null);
    const [msgList, setMsgList] = useState<Record<string, ITemporaryMessage[]>>({});
    const [isNewMsg, setIsNewMsg] = useState<Record<string, boolean>>({});
    const isShowAddFriend = useMemo(() => {
        if (!selectId) return false;
        if (!msgList[selectId]) return false;
        //不在好友列表中
        if (!user.friendsList?.map((f) => f.friendId).includes(selectId)) {
            //往复消息超过两条
            const allKey = Object.keys(
                msgList[selectId].reduce((p, c) => {
                    p[c.sender] = 1;
                    return p;
                }, {} as Record<string, number>)
            );
            return allKey.length > 1;
        }
        return false;
    }, [msgList, selectId, user.friendsList]);

    useEffect(() => {
        if (selectId) {
            inputRef.current?.focus();
            CanRun.startInput();
            setIsNewMsg((prev) => ({ ...prev, [selectId]: false }));
        }
        selectIdRef.current = selectId;
    }, [selectId]);

    useEffect(() => {
        selectIndexRef.current = selectIndex;
        const user = nearbyUsers[selectIndex - 1];
        if (user) {
            setSelectId(nearbyUsers[selectIndex - 1]._id);
            console.log(user);
        } else setSelectId("");
        //不能根据nearbyUsers变化 太过频繁 只在selectIndex变化时获取即可
        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [selectIndex]);

    const cancelInput = useCallback(() => {
        //结束选择
        setSelectIndex(-1);
        inputting.current = false;
        inputRef.current && (inputRef.current.value = "");
        CanRun.endInput();
    }, []);

    const sendMessage = useCallback(
        (e?: MouseEvent) => {
            //阻止事件冒泡
            e?.stopPropagation();
            if (!inputRef.current) return new Error("未获取inputRef");
            const content = inputRef.current.value;
            if (!content) return cancelInput();
            const send = {
                content,
                to: selectIdRef.current,
                from: user._id!,
                senderName: user.name!,
            };
            SocketManager.emit("temporaryMessage", send);
            //本地填充
            const msg = {
                content,
                sender: send.from,
                senderName: send.senderName,
            };
            setMsgList((prev) => ({ ...prev, [send.to]: [...(prev[send.to] || []), msg] }));
            if (inputRef.current) {
                inputRef.current.value = "";
                // inputRef.current.blur();
            }
            // CanRun.endInput();
        },
        [cancelInput, user._id, user.name]
    );

    const keyListen = useCallback(
        (e: KeyboardEvent) => {
            const num = +e.key;
            //没有输入的时候按下键
            if (!inputting.current) {
                //只响应数字键 && 不为0 && 按下的数字有对应的数据(长度不能大于附近人数)
                if (!isNaN(num) && num && num <= payloadIndex.current) {
                    setSelectIndex(num);
                    inputting.current = true;
                }
            }
            // 输入时 按下回车 发送
            else if (e.key == "Enter") {
                if (inputRef.current && inputRef.current.value) {
                    sendMessage();
                }
                //发送消息
                else cancelInput();
            }
            // 输入时 按下以选中索引 取消对话
            // 防止输入数字正好对应索引意外取消
            else if (num == selectIndexRef.current) {
                if (inputRef.current && !inputRef.current.value) cancelInput();
            }
        },
        [cancelInput, sendMessage]
    );

    useEffect(() => {
        otherUserList.nearbyUsersChange((nearbyUsers) => {
            // console.log(nearbyUsers);
            setNearbyUsers(nearbyUsers);
            payloadIndex.current = nearbyUsers.length;
        });
        SocketManager.listen("temporaryMessage", (msg: ITemporaryMessage) => {
            console.log("临时消息:", msg);

            setMsgList((prev) => ({ ...prev, [msg.sender]: [...(prev[msg.sender] || []), msg] }));
            if (selectIdRef.current != msg.sender) setIsNewMsg((prev) => ({ ...prev, [msg.sender]: true }));
        });
    }, []);

    /**
     * 开启时监听按键
     */
    useEffect(() => {
        document.addEventListener("keypress", keyListen);
        return () => {
            document.removeEventListener("keypress", keyListen);
        };
    }, [keyListen]);

    useEffect(() => {
        if (inputRef.current) {
            const blurListen = () => {
                CanRun.endInput();
            };
            inputRef.current.addEventListener("blur", blurListen);

            return () => {
                if (inputRef.current) {
                    inputRef.current.removeEventListener("blur", blurListen);
                }
            };
        }
    }, [selectId]);

    const InputComponent = useMemo(
        () => (
            <InputWrap>
                <input onChange={(e) => (inputting.current = !!e.target.value)} ref={inputRef} type="text" />
                <button onClick={sendMessage}>
                    <svg
                        viewBox="0 0 1024 1024"
                        version="1.1"
                        xmlns="http://www.w3.org/2000/svg"
                        p-id="2045"
                        width="16"
                        height="16"
                    >
                        <path
                            d="M417 1c-48.602 0-88 39.399-88 88v346H89c-48.6 0-88 39.399-88 88v412c0 48.6 39.4 88 88 88h314.69c4.341 0.658 8.786 1 13.31 1h517c24.555 0 46.761-10.057 62.724-26.277C1012.943 981.761 1023 959.555 1023 935V523c0-4.524-0.341-8.968-1-13.31V89c0-48.601-39.398-88-88-88H417z m250.036 645.739V389.131c0-27.134 21.977-49.131 49.087-49.131 27.11 0 49.088 21.997 49.088 49.131V745H453.699l31.657 31.657c19.174 19.173 19.167 50.263-0.012 69.441-19.178 19.179-50.268 19.185-69.441 0.013L266 696.207l149.956-149.955c19.179-19.179 50.269-19.185 69.441-0.013 19.172 19.173 19.167 50.263-0.012 69.441l-31.059 31.059h212.71z"
                            p-id="2046"
                            fill="#ffffff"
                        ></path>
                    </svg>
                </button>
            </InputWrap>
        ),
        [sendMessage]
    );

    const requestAddFriend = useCallback(() => {
        SocketManager.emit("requestAddFriend", {
            applicant: user._id,
            applicantName: user.name,
            respondent: selectIdRef.current,
        });
    }, [user._id, user.name]);

    return nearbyUsers.length ? (
        <Container>
            <Title>附近的人</Title>
            <Caption>按下对应键快捷对话或点击</Caption>
            {nearbyUsers.map((user, index) => (
                <Fragment key={user._id}>
                    <Dialogue
                        onClick={() => {
                            if (user._id === selectId) {
                                cancelInput();
                            } else setSelectIndex(index + 1);
                        }}
                        component={
                            user._id == selectId ? (
                                <Fragment>
                                    <MessageList list={msgList[user._id] || []} />
                                    {InputComponent}
                                    {isShowAddFriend ? <AddFriend onClick={requestAddFriend}>加好友</AddFriend> : null}
                                </Fragment>
                            ) : undefined
                        }
                        select={user._id === selectId}
                        user={user}
                        index={index + 1}
                        isNewMsg={isNewMsg[user._id]}
                    />
                </Fragment>
            ))}
        </Container>
    ) : null;
};

export default memo(TemporaryDialogue);

const AddFriend = styled.button`
    width: 100%;
    padding: 0.3vh;
    border: none;
    background: #299417;
    color: #fff;
    cursor: pointer;
    animation: ${fadeIn} 0.7s;
    margin-top: 4px;
`;

const InputWrap = styled(FlexDiv)`
    background: #19570d;
    input {
        outline: none;
        border: none;
        padding: 4px;
        background-color: #103d07;
        color: #fff;
        width: 70%;
    }
    button {
        width: 28%;
        margin-left: 2%;
        font-size: 1vw;
        background-color: #1d6c0e;
        border: none;
        color: #fff;
        padding: 3px 1vmax;
        ${flexCenter};
        transition: all 0.3s;
        svg {
            width: 1.5vmax;
            height: 1.5vmax;
        }
        :hover {
            background-color: #fff;
            path {
                fill: #1d6c0e;
            }
        }
    }
`;

const Container = styled.div`
    position: absolute;
    background: #ffffff2b;
    z-index: 11;
    top: 20vh;
    right: 20vw;
    width: 17vw;
    display: flex;
    border-radius: 0.3vw;
    flex-direction: column;
    padding: 1vh 1vw;
    max-height: 70vh;
    /* height: 70vh; */
    overflow: hidden scroll;
    //隐藏滚动条
    ::-webkit-scrollbar-thumb {
        background: transparent;
        display: none;
    }
    scrollbar-color: transparent transparent;
    ::-webkit-scrollbar {
        background-color: transparent;
        display: none;
    }
`;

const Title = styled.p`
    //firefox没有最小12px限制 使用vw要谨慎勇max兜底
    font-size: max(1vw, 12px);
    color: #234f12;
`;

const Caption = styled.span`
    font-size: max(0.7vw, 10px);
    color: #2f5f1d;
`;
